package com.pansoft.openplanet.util;

import com.pansoft.hd.HDWalletUtil;

import org.bitcoinj.crypto.ChildNumber;
import org.bitcoinj.crypto.DeterministicHierarchy;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.HDKeyDerivation;
import org.bitcoinj.crypto.HDUtils;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.wallet.DeterministicKeyChain;
import org.bitcoinj.wallet.DeterministicSeed;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Keys;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

/**
 * 以太坊助记词
 * 用到了比特币的jar包 org.bitcoinj
 * 测试网址 https://iancoleman.io/bip39/#english
 */
public class EthMnemonicUtilsTest {

    private static String ETH_TYPE = "m/44'/60'/0'/0/0";

    /**
     * 使用助记词种子生成密钥
     *
     * @param ds
     * @return
     */
    public static ECKeyPair generateECPair(DeterministicSeed ds) {
        DeterministicKey dkKey = HDKeyDerivation.createMasterPrivateKey(ds.getSeedBytes());
        String[] pathArray = ETH_TYPE.split("/");
        for (int i = 1; i < pathArray.length; i++) {
            ChildNumber childNumber;
            if (pathArray[i].endsWith("'")) {
                int number = Integer.parseInt(pathArray[i].substring(0,
                        pathArray[i].length() - 1));
                childNumber = new ChildNumber(number, true);
            } else {
                int number = Integer.parseInt(pathArray[i]);
                childNumber = new ChildNumber(number, false);
            }
            dkKey = HDKeyDerivation.deriveChildKey(dkKey, childNumber);
        }

        ECKeyPair keyPair = ECKeyPair.create(dkKey.getPrivKeyBytes());
        System.out.println("createECKeyPairFromSeed:"+ Keys.getAddress(keyPair));
        return keyPair;
    }


    /**
     * 使用助记词和密码生成私钥（基于eth）
     *
     * @param mnemonic 助记词
     * @param passWord 密码(密码现在使用"")
     * @return
     * @throws Exception
     */
    public static String generatePrivateKey(String mnemonic, String passWord) throws Exception {

        MainNetParams mainnetParams = MainNetParams.get();
        List<String> list= HDWalletUtil.mnemonicString2List(mnemonic);
        long creationTimeSeconds = System.currentTimeMillis() / 1000;
        DeterministicSeed deterministicSeed = new DeterministicSeed(list, null, passWord, creationTimeSeconds);
        System.out.println("16进制seed值为：" + deterministicSeed.toHexString());
        DeterministicKey rootPrivateKey = HDKeyDerivation.createMasterPrivateKey(deterministicSeed.getSeedBytes());
//        System.out.println("16进制rootPrivateKey值: " + rootPrivateKey.getPrivateKeyAsHex());


        /**根私钥进行 priB58编码*/
        String priv = rootPrivateKey.serializePrivB58(mainnetParams);
        System.out.println("BIP32RootKey(根密钥)值: " + priv);
//        System.out.println("主链码 (master chain code)值: " + Utils.HEX.encode(rootPrivateKey.getChainCode()) );
        System.out.println("------------------------------");

        //todo 生成成HD钱包方式1
        DeterministicKeyChain keyChain = DeterministicKeyChain.builder().seed(deterministicSeed).build();
        List<ChildNumber> zeroPath = HDUtils.parsePath("M/44H/60H/0H/0/0");
        byte[] prvKeyBytes = keyChain.getKeyByPath(zeroPath, true).getPrivKeyBytes();
        ECKeyPair childEcKeyPair111 = ECKeyPair.create(prvKeyBytes);
        System.out.println("钱包地址为:" + "0x" + Keys.getAddress(childEcKeyPair111));

        //todo 方式2
       // createECKeyPairFromSeed(ds);

        //todo 测试btc
//       ECKey ecKey= BTCMnemonicUtils.generateECKey(deterministicSeed);
//        Address myAddress = LegacyAddress.fromKey(MainNetParams.get(), ecKey);
//        System.out.println("打印btc地址："+myAddress);

        /**由根私钥生成HD钱包*/
        DeterministicHierarchy deterministicHierarchy = new DeterministicHierarchy(rootPrivateKey);
        /**定义父路径*/
        List<ChildNumber> parsePath = HDUtils.parsePath("44H/60H/0H");

        DeterministicKey accountKey0 = deterministicHierarchy.get(parsePath, true, true);

        System.out.println("Account extended private key值: " + accountKey0.serializePrivB58(mainnetParams));
        System.out.println("Account extended public key值: " + accountKey0.serializePubB58(mainnetParams));
        System.out.println("Account getPathAsString: " + accountKey0.getPathAsString());
        System.out.println("Account depth："+accountKey0.getDepth());
//        System.out.println("主链码 (master chain code)值: " + Utils.HEX.encode(accountKey0.getParent().getChainCode()) );
//        System.out.println("主链码 (Account chain code)值: " + Utils.HEX.encode(accountKey0.getChainCode()) );

        System.out.println("------------------------------");

        /**由父路径,派生出第一个子私钥*/
        DeterministicKey childKey0 = HDKeyDerivation.deriveChildKey(accountKey0, 0);
        System.out.println("walletchain depth："+childKey0.getDepth());

        System.out.println("BIP32 extended 0 private key: " + childKey0.serializePrivB58(mainnetParams));
        System.out.println("BIP32 extended 0 public key: " + childKey0.serializePubB58(mainnetParams));
//        System.out.println("0 private key: "+ childKey0.getPrivateKeyAsHex());
//        System.out.println("0 public key: "+ childKey0.getPublicKeyAsHex());
//        System.out.println("0 getPathAsString: "+ childKey0.getPathAsString());
//
//        ECKeyPair childEcKeyPair0 = ECKeyPair.create(childKey0.getPrivKeyBytes());
//        System.out.println("0 钱包地址为:"+"0x" + Keys.getAddress(childEcKeyPair0));


        System.out.println("------------------------------");

        //生成钱包
//        派生地址
//        请注意，这些地址是从BIP32扩展密钥派生的
        for (int i = 0; i < 3; i++) {
            DeterministicKey deriveChildKey = HDKeyDerivation.deriveChildKey(childKey0, i);

//            System.out.println("派生地址depth："+deriveChildKey.getDepth());
            ECKeyPair childEcKeyPair0 = ECKeyPair.create(deriveChildKey.getPrivKeyBytes());
//            System.out.println("public key: "+ deriveChildKey.getPublicKeyAsHex());
            System.out.println("钱包地址为:" + "0x" + Keys.getAddress(childEcKeyPair0));

            System.out.println(deriveChildKey.toString());
//        System.out.println("------------------------------");
        }

        //todo 测试wallet


        //TODO 父公钥推导子 公钥


//        DeterministicKey child1=   HDKeyDerivation.deriveChildKeyBytesFromPublic(childKey0,new ChildNumber(1),
//                HDKeyDerivation.PublicDeriveMode.WITH_INVERSION);
//        System.out.println("派生地址depth："+child1.getDepth());
//
//        System.out.println("child1 getPathAsString: " + child1.getPathAsString());
//
////        ECKeyPair childEcKeyPair0 = ECKeyPair.create(child1.getPrivKeyBytes());
//        System.out.println("child1 钱包地址为:" + "0x" + Keys.getAddress(child1.getPubKey()));


////        /**由父路径,派生出第二个子私钥*/
//        DeterministicKey childKey1 = HDKeyDerivation.deriveChildKey(accountKey0, 1);
//        System.out.println("BIP32 extended 1 private key:"+ childKey1.serializePrivB58(mainnetParams));
//        System.out.println("BIP32 extended 1 public key:"+ childKey1.serializePubB58(mainnetParams));
//
//        System.out.println("1 private key:"+ childKey1.getPrivateKeyAsHex());
//        System.out.println("1 public key:"+ childKey1.getPublicKeyAsHex());
//        System.out.println("1 getPathAsString :"+ childKey1.getPathAsString());
//
//        ECKeyPair childEcKeyPair1 = ECKeyPair.create(childKey1.getPrivKeyBytes());
//        System.out.println("1 钱包地址为: "+"0x" + Keys.getAddress(childEcKeyPair1));


//        String bip44 = "m/44'/60'/0'/0/0";
//
//        String[] pathArray = bip44.split("/");
//        for (int i = 1; i < pathArray.length; i++) {
//            ChildNumber childNumber;
//            if (pathArray[i].endsWith("'")) {
//                int number = Integer.parseInt(pathArray[i].substring(0,
//                        pathArray[i].length() - 1));
//                childNumber = new ChildNumber(number, true);
//            } else {
//                int number = Integer.parseInt(pathArray[i]);
//                childNumber = new ChildNumber(number, false);
//            }
//            rootPrivateKey = HDKeyDerivation.deriveChildKey(rootPrivateKey, childNumber);
//        }
//        System.out.println("path " + rootPrivateKey.getPathAsString());
//
//        System.out.println(rootPrivateKey.getPrivateKeyAsHex());
        return null;
    }

    public static void main(String[] args) {
        try {
//            generatePrivateKey("plug bundle alter bleak output prison adult crater thing ramp slight scheme", "123456");
            generatePrivateKey("guilt brave spirit agent silly embody switch update jungle behave gold issue", "");
//guilt brave spirit agent silly embody switch update jungle behave gold issue
            //createHDWalletByPATH("plug bundle alter bleak output prison adult crater thing ramp slight scheme", "123456",number);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static void createHDWalletByPATH(String word, String passphrase, int[] childNum) throws FileNotFoundException, IOException {
        try {
            DeterministicSeed deterministicSeed = new DeterministicSeed(word, null, passphrase, 0L);
            System.out.println("16进制seed值为：" + deterministicSeed.toHexString());

            DeterministicKeyChain deterministicKeyChain = DeterministicKeyChain.builder().seed(deterministicSeed).build();
            DeterministicKey main = deterministicKeyChain.getKeyByPath(HDUtils.parsePath("44H/60H/0H"), true);
            String priv = main.serializePrivB58(MainNetParams.get());
            System.out.println("account extend private key值: " + priv);

            DeterministicHierarchy tree = new DeterministicHierarchy(main);
            DeterministicKey rootKey = tree.getRootKey();
            for (int i = childNum[0], len = childNum[1]; i < len; i++) {
                DeterministicKey deriveChildKey = HDKeyDerivation.deriveChildKey(rootKey, new ChildNumber(i));
                            System.out.println("public key: "+ deriveChildKey.getPublicKeyAsHex());

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}